const fs = require('fs-extra');
const chalk = require('chalk');
const signale = require('signale');

/**
 * Remove empty files.
 *
 * @param {Object} filePaths
 */
const removeEmptyFiles = (filePaths) => {
  filePaths.forEach((filePath) => {
    if (fs.existsSync(filePath)) {
      const fileContent = fs.readFileSync(filePath, 'utf-8').trim();

      if ('' === fileContent) {
        fs.unlinkSync(filePath);
      }
    }
  });
};

class DownloadState {
  constructor() {
    this.currentlyDownloading = {};
    this.currentlyDownloadingPaths = [];
    this.downloading = false;
    this.numberTracksFinished = 0;
    this.numberTracksToDownload = 0;
    this.downloadType = '';
    this.downloadTypeId = 0;
    this.downloadTypeName = '';
    this.downloadedSuccessfully = null;
    this.downloadedUnsuccessfully = null;
    this.downloadedWithWarning = null;

    // pending messages
    this.messages = [];
  }

  start(downloadType, downloadTypeId) {
    this.downloading = true;
    this.downloadType = downloadType;
    this.downloadTypeId = downloadTypeId;

    this.downloadedSuccessfully = fs.createWriteStream('success.txt', {
      flags: 'a', // 'a' means appending (old data will be preserved)
    });

    this.downloadedUnsuccessfully = fs.createWriteStream('error.txt', {
      flags: 'a', // 'a' means appending (old data will be preserved)
    });

    this.downloadedWithWarning = fs.createWriteStream('warning.txt', {
      flags: 'a', // 'a' means appending (old data will be preserved)
    });

    // this.display();
  }

  updateNumberTracksToDownload(numberTracksToDownload) {
    this.numberTracksToDownload = numberTracksToDownload;
  }

  finish(showFinishMessage = true) {
    this.downloading = false;

    if (showFinishMessage) {
      let downloadTypeAndName = this.downloadType;

      if (this.downloadTypeName) {
        downloadTypeAndName += ' "' + this.downloadTypeName + '"';
      }

      console.log('');
      for (const m of this.messages) {
        signale[m.type](m.message);
      }
      this.messages = [];
      signale.complete('Finished downloading ' + downloadTypeAndName);
    }

    if ('-' !== this.downloadTypeId.toString().charAt(0)) {
      this.downloadedSuccessfully.write(
        'https://www.deezer.com/' + this.downloadType + '/' + this.downloadTypeId + '\r\n'
      );
    }

    this.downloadedSuccessfully.end();
    this.downloadedUnsuccessfully.end();
    this.downloadedWithWarning.end();

    removeEmptyFiles(['downloadedSuccessfully.txt', 'downloadedUnsuccessfully.txt', 'downloadedWithWarning.txt']);

    this.currentlyDownloading = {};
    this.currentlyDownloadingPaths = [];
    this.numberTracksFinished = 0;
    this.numberTracksToDownload = 0;
    this.downloadType = '';
    this.downloadTypeId = 0;
    this.downloadTypeName = '';
  }

  setDownloadTypeName(downloadTypeName) {
    this.downloadTypeName = downloadTypeName;
    // this.display();
  }

  add(trackId, message) {
    this.currentlyDownloading[trackId] = message;
    // this.display();
  }

  update(trackId, message) {
    this.add(trackId, message);
  }

  remove(trackId) {
    delete this.currentlyDownloading[trackId];
    // this.display();
  }

  success(trackId, message) {
    // signale.success(message);
    this.messages.push({
      type: 'success',
      message,
    });
    this.numberTracksFinished++;
    this.remove(trackId);
  }

  warn(trackId, message) {
    // signale.warn(message);
    this.messages.push({
      type: 'warn',
      message,
    });
    if ('-' !== trackId.toString().charAt(0)) {
      this.downloadedWithWarning.write('https://www.deezer.com/track/' + trackId + '\r\n');
    }
    this.numberTracksFinished++;
    this.remove(trackId);
  }

  fail(trackId, message) {
    // signale.fatal(message);
    this.messages.push({
      type: 'fatal',
      message,
    });
    if ('-' !== trackId.toString().charAt(0)) {
      this.downloadedUnsuccessfully.write('https://www.deezer.com/track/' + trackId + '\r\n');
    }
    this.numberTracksFinished++;
    this.remove(trackId);
  }

  display() {
    if (this.downloading) {
      let downloadTypeAndName = this.downloadType;

      if (this.downloadTypeName) {
        downloadTypeAndName += ' "' + this.downloadTypeName + '"';
      }

      let finishedPercentage = '0.00';

      if (0 !== this.numberTracksToDownload) {
        finishedPercentage = ((this.numberTracksFinished / this.numberTracksToDownload) * 100).toFixed(2);
      }

      let downloadSpinnerText = chalk.green(
        'Downloading ' +
          downloadTypeAndName +
          ' [' +
          this.numberTracksFinished +
          '/' +
          this.numberTracksToDownload +
          ' - ' +
          finishedPercentage +
          '%]:\n'
      );

      if (0 < Object.keys(this.currentlyDownloading).length) {
        downloadSpinnerText += '  › ' + Object.values(this.currentlyDownloading).join('\n  › ');
      } else {
        downloadSpinnerText += '  › Fetching infos...';
      }

      signale.info(downloadSpinnerText);
    }
  }

  addCurrentlyDownloadingPath(downloadPath) {
    this.currentlyDownloadingPaths.push(downloadPath);
  }

  removeCurrentlyDownloadingPath(downloadPath) {
    const index = this.currentlyDownloadingPaths.indexOf(downloadPath);
    if (-1 !== index) {
      this.currentlyDownloadingPaths.splice(index, 1);
    }
  }

  isCurrentlyDownloadingPathUsed(downloadPath) {
    return this.currentlyDownloadingPaths.indexOf(downloadPath) > -1;
  }
}

const downloadState = new DownloadState();
module.exports = downloadState;
